package com.liwenxu;

import android.content.Context;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.media.Image;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.os.Environment;
import android.os.SystemClock;
import android.util.Log;

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;

import static com.example.tutk.VideoPlay.se;

/**
 * Created by 李文旭 on 2018/9/9.
 */

public class decodeThread implements  Runnable {
    public static int stop = 0;//线程是否需要关闭
    public AudioTrack track;
    public MediaCodec decoder;
    public  MediaMuxer muxer;
    public MediaFormat videoFormat;
    public MediaFormat audioFormat;
    public static boolean finishedMp4 = false;//是否正在录像
    public int videoTrackIndex;
    public int AudioTrackIndex;
    public MediaCodec Audioencoder;
    public boolean isStart=false;//录像是否已经开启
    public decodeThread() {
    }

    private int bytes2Int(byte[] bt) {
        int ret = bt[0];
        ret <<= 8;
        ret |= bt[1];
        return ret;
    }

    @Override
    public void run() {
        while (stop == 0) {
            System.out.printf("123123123132131231231213");
            try {
                initVideoFormat();
                initVideoDecoder();
                initAudioEncoder();
                initMuxer();
                initAudioTrack();
            }catch (Exception e) {
                    e.printStackTrace();//捕获异常继续while循环解码
                }
                while (stop == 0) {
                    //Log.d("wait","sadadsad");
                    try {
                        framInfo frame = VideoPlay.queue.poll();
                        framInfo AudioInfo = VideoPlay.AudioQueue.poll();
                        if(finishedMp4&&!isStart)
                        {
                            muxer.start();
                            Audioencoder.start();
                            isStart=true;
                        }
                        if (frame == null && AudioInfo == null)
                            continue;
                        if (frame != null) {//视频解码
                            decodeVideo(decoder, frame, muxer);
                        }
                        if(AudioInfo!=null){//音频编码
                              isStart=true;
                              track.write(AudioInfo.data, 0, AudioInfo.size);
                              if(finishedMp4) {
                                  encodeAudio(Audioencoder, AudioInfo, muxer);
                              }
                        }
                    }
                    catch (MediaCodec.CryptoException e)
                    {
                        Log.e("exception "," "+e.getErrorCode());
                    }
                }
                decoder.stop();decoder.release();
                Audioencoder.stop();Audioencoder.release();
                muxer.stop();muxer.release();
        }
    }



    public void decodeVideo(MediaCodec decoder, framInfo frame, MediaMuxer muxer) {
        int inputBufIndex = decoder.dequeueInputBuffer(-1);
        ByteBuffer inputBuffer = null;
        if (inputBufIndex >= 0) {
            inputBuffer = decoder.getInputBuffer(inputBufIndex);
            // fill inputBuffer with valid data
            MediaFormat outputFormat = decoder.getOutputFormat();
            inputBuffer.clear();
            inputBuffer.put(frame.data);
            decoder.queueInputBuffer(inputBufIndex, 0, frame.size, 5 * frame.index, 0);
        }
        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
        if(isStart) {
            if (finishedMp4) {
                muxer.writeSampleData(videoTrackIndex, getBuffer(frame), getInfo(frame));
                Log.d("xieru1", " ");
            } else {
                muxer.stop();Audioencoder.stop();
                muxer.release();Audioencoder.release();
                isStart=false;
            }
        }
        int outputBufferId = decoder.dequeueOutputBuffer(info, 0);
        Log.d("jiema", " " + outputBufferId + " " + info.presentationTimeUs + " ");
        while (outputBufferId >= 0) {
            ByteBuffer outputBuffer = decoder.getOutputBuffer(outputBufferId);
            MediaFormat bufferFormat = decoder.getOutputFormat(outputBufferId); // option A
            decoder.releaseOutputBuffer(outputBufferId, true);
            outputBufferId = decoder.dequeueOutputBuffer(info, 0);
        }
        if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            MediaFormat outputFormat = decoder.getOutputFormat(); // option B
        }
    }
    public void encodeAudio(MediaCodec encoder, framInfo frame, MediaMuxer muxer)
    {
        int inputBufIndex = encoder.dequeueInputBuffer(-1);
        ByteBuffer inputBuffer = null;
        if (inputBufIndex >= 0) {
            inputBuffer = encoder.getInputBuffer(inputBufIndex);
            // fill inputBuffer with valid data
            MediaFormat outputFormat = encoder.getOutputFormat();
            inputBuffer.clear();
            inputBuffer.put(frame.data);
            encoder.queueInputBuffer(inputBufIndex, 0, frame.size, 5 * frame.index, 0);
        }
        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
        int outputBufferId = encoder.dequeueOutputBuffer(info, 0);
        Log.d("bianma", " " + outputBufferId + " " + info.presentationTimeUs);
        while (outputBufferId >= 0) {
            ByteBuffer outputBuffer = encoder.getOutputBuffer(outputBufferId);
            MediaFormat bufferFormat = encoder.getOutputFormat(outputBufferId); // option A
            if(isStart) {
                if (finishedMp4) {
                    outputBuffer.position(info.offset);
                    outputBuffer.limit(info.offset + info.size);
                    AudioTrackIndex = muxer.addTrack(bufferFormat);
                    muxer.writeSampleData(AudioTrackIndex,outputBuffer,info);
                    Log.d("xieru2", " " + frame.data+" "+info.size);
                } else {
                    muxer.stop();Audioencoder.stop();
                    muxer.release();Audioencoder.release();
                    isStart=false;
                }
            }
            encoder.releaseOutputBuffer(outputBufferId, true);
            outputBufferId = encoder.dequeueOutputBuffer(info, 0);
        }
        if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            MediaFormat outputFormat = encoder.getOutputFormat(); // option B
        }
    }
    public  ByteBuffer getBuffer(framInfo frame)
    {
        ByteBuffer byteBuffer=ByteBuffer.allocate(frame.size);
        byteBuffer.put(frame.data);
        Log.d("debug","  "+byteBuffer.remaining()+" "+byteBuffer.limit()+" "+byteBuffer.position());
        return byteBuffer;
    }
    public MediaCodec.BufferInfo getInfo(framInfo frame)
    {
        MediaCodec.BufferInfo info =new MediaCodec.BufferInfo();
        info.offset = 0;
        info.size = frame.size;
        info.flags = MediaCodec.BUFFER_FLAG_SYNC_FRAME;
        info.presentationTimeUs = frame.index*5;
        return info;
    }
    private void initMuxer() throws IOException {
        muxer = new MediaMuxer("/data/data/com.example.tutk/downdown/" + "/temp.mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
        videoTrackIndex = muxer.addTrack(videoFormat);
        AudioTrackIndex = muxer.addTrack(audioFormat);
    }

    private void initAudioEncoder() throws IOException {
        audioFormat = MediaFormat.createAudioFormat(
                MediaFormat.MIMETYPE_AUDIO_AAC, 8000, 2);
        audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, 96000);
        Audioencoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
        Audioencoder.configure(audioFormat, null, null,
                MediaCodec.CONFIGURE_FLAG_ENCODE);
    }

    private void initVideoFormat() {
        videoFormat = MediaFormat.createVideoFormat("video/avc", 640, 368);
        //MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", (H264SPSPaser.ue(VideoPlay.mSps, 34) + 1) * 16, (H264SPSPaser.ue(VideoPlay.mSps, -1) + 1) * 16);
        videoFormat.setByteBuffer("csd-0", ByteBuffer.wrap(VideoPlay.mSps));
        videoFormat.setByteBuffer("csd-1", ByteBuffer.wrap(VideoPlay.mPps));
    }

    private void initVideoDecoder() throws IOException {
        decoder = MediaCodec.createDecoderByType("video/avc");
        decoder.configure(videoFormat, se.getSurface(), null, 0);
        decoder.start();
    }

    private void initAudioTrack() {
        int bufferSize = AudioTrack.getMinBufferSize(8000,
                AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
        track = new AudioTrack(AudioManager.STREAM_MUSIC,
                8000,
                AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize,
                AudioTrack.MODE_STREAM);
        track.play();
    }
}
